package com.simpleplayer.contentview.gles;

import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
import java.nio.ShortBuffer;

import android.opengl.GLES11Ext;
import android.opengl.GLES20;

public class DirectRenderer extends GLESRenderer {

    private final String vertexShaderCode =
            "attribute vec4 vPosition;" +
                    "attribute vec2 inputTextureCoordinate;" +
                    "varying vec2 textureCoordinate;" +
                    "void main() {" +
                    "gl_Position = vPosition;" +
                    "textureCoordinate = inputTextureCoordinate;" +
                    "}";

    private final String fragmentShaderCode =
            "#extension GL_OES_EGL_image_external : require\n"+
                    "precision mediump float;" +
                    "varying vec2 textureCoordinate;\n" +
                    "uniform samplerExternalOES video_frame_texture;\n" +
                    "void main() {" +
                    "    gl_FragColor = texture2D(video_frame_texture, textureCoordinate);\n" +
                    "}";

    private final FloatBuffer vertexBuffer;
    private final FloatBuffer textureVerticesBuffer;
    private final ShortBuffer drawListBuffer;

    private ShaderProgram mShaderProgram;

    // order to draw vertices
    private final short[] drawOrder = {0, 1, 2, 0, 2, 3};

    // number of coordinates per vertex in this array
    private static final int COORDS_PER_VERTEX = 2;

    // EGLDiplay is center coordinate system.
    // 1.0f means the edge of display square. left bottom is (-1,-1)
    static float[] squareCoords = {
            -1.0f,  1.0f,
            -1.0f, -1.0f,
            1.0f, -1.0f,
            1.0f,  1.0f,
    };

    // SurfaceTexture's texture, left bottom is (0,0)
    static float[] textureVertices = {
            0.0f, 0.0f,
            0.0f, 1.0f,
            1.0f, 1.0f,
            1.0f, 0.0f,
    };

    private boolean mInited = false;

    public DirectRenderer() {

        // initialize vertex byte buffer for shape coordinates
        ByteBuffer bb = ByteBuffer.allocateDirect(squareCoords.length * 4);
        bb.order(ByteOrder.nativeOrder());
        vertexBuffer = bb.asFloatBuffer();
        vertexBuffer.put(squareCoords);
        vertexBuffer.position(0);

        // initialize byte buffer for the draw list
        ByteBuffer dlb = ByteBuffer.allocateDirect(drawOrder.length * 2);
        dlb.order(ByteOrder.nativeOrder());
        drawListBuffer = dlb.asShortBuffer();
        drawListBuffer.put(drawOrder);
        drawListBuffer.position(0);

        ByteBuffer bb2 = ByteBuffer.allocateDirect(textureVertices.length * 4);
        bb2.order(ByteOrder.nativeOrder());
        textureVerticesBuffer = bb2.asFloatBuffer();
        textureVerticesBuffer.put(textureVertices);
        textureVerticesBuffer.position(0);

        //initGLProgram();
    }

    // note: if GLContext is changed, should redo init GL Program and link to new GLContext.
    @Override
    public void initGLProgram() {
        mShaderProgram = new ShaderProgram(vertexShaderCode, fragmentShaderCode);
        // get handle to vertex shader's vPosition member
        mInited = true;
    }

    @Override
    public boolean isInited() {
        return mInited;
    }

    @Override
    public void drawFrame(int texture, float[] mtx) {

        GLES20.glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
        GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT | GLES20.GL_DEPTH_BUFFER_BIT);
        GLES20.glUseProgram(mShaderProgram.getShaderHandle());

        int mPositionHandle = mShaderProgram.getAttribute("vPosition");
        int mTextureCoordHandle = mShaderProgram.getAttribute("inputTextureCoordinate");

        //// Enable a handle to the triangle vertices
        GLES20.glEnableVertexAttribArray(mPositionHandle);
        GLHelper.checkGlError("glEnableVertexAttribArray");

        //// Prepare the <insert shape here> coordinate data
        // 4 bytes per vertex
        int vertexStride = COORDS_PER_VERTEX * 4;
        GLES20.glVertexAttribPointer(mPositionHandle,
                COORDS_PER_VERTEX, GLES20.GL_FLOAT, false, vertexStride, vertexBuffer);
        GLHelper.checkGlError("glVertexAttribPointer");

        GLES20.glEnableVertexAttribArray(mTextureCoordHandle);
        GLHelper.checkGlError("glEnableVertexAttribArray");

        GLES20.glVertexAttribPointer(mTextureCoordHandle,
                COORDS_PER_VERTEX, GLES20.GL_FLOAT, false, vertexStride, textureVerticesBuffer);
        GLHelper.checkGlError("glVertexAttribPointer");

        // bind the texture to GL_TEXTURE0(s_texture define in the frament shader code).
        GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
        GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, texture);

        GLES20.glDrawElements(GLES20.GL_TRIANGLES,
                drawOrder.length, GLES20.GL_UNSIGNED_SHORT, drawListBuffer);

        GLES20.glDisableVertexAttribArray(mPositionHandle);
        GLES20.glDisableVertexAttribArray(mTextureCoordHandle);

    }

    @Override
    public void updateViewport(int width, int height) {
    }

    @Override
    public void updateCamera(float deltaX, float deltaY) {
    }

    @Override
    public void releaseGLProgram() {
        mShaderProgram.release();
        mInited = false;
    }
}


